// const bigNumber = BigInt(Number.MAX_SAFE_INTEGER)
// console.log(bigNumber)
// console.log(bigNumber + 1n, bigNumber + 2n)
// console.log(bigNumber + 1n === bigNumber + 2n) // false 因为这里是BigInt类型的比较  9007199254740992n 和 9007199254740993n 不相等

// console.log(Number.MAX_SAFE_INTEGER + 1, Number.MAX_SAFE_INTEGER + 2)
// console.log(Number.MAX_SAFE_INTEGER + 1 === Number.MAX_SAFE_INTEGER + 2) // true 因为这里是Number类型的比较  9007199254740992 和 9007199254740992 相等

// function getThis() {
//   // 'use strict' // 严格模式下，this指向调用者的上下文，否则(非严格模式)指向全局对象 如果函数在没有被任何东西访问的情况下被调用，this 将是 undefined
//   return this
// }
// console.log(getThis())
// // 仅用于演示——你不应该修改内置的原型对象
// Number.prototype.getThis = getThis
// console.log(typeof (1).getThis()) // "object"
// console.log(getThis() === globalThis) // true

// function logThis() {
//   // 'use strict'
//   console.log(this)
// }
// 一些 API 允许你为回调函数的调用设置一个 this 值。例如，所有的迭代数组方法和相关的方法，如Set.prototype.forEach()，都接受一个可选的 thisArg 参数。
// const array = ['a', 'b', 'c']
// array.forEach(logThis, 'thisArg')

// array.forEach(logThis)

// 偶尔，回调函数会以一个非 undefined 的 this 值被调用。例如，JSON.parse() 的 reviver 参数和 JSON.stringify() 的 replacer 参数都会把 this 设置为正在被解析/序列化的属性所属的对象。
// const json = '{"a":1}'
// const obj = JSON.parse(json, function (key, value) {
//   console.log(key, value, this)
//   return value
// })

// 如果源代码作为模块加载（对于 HTML，这意味着在 <script> 标签中添加 type="module"），在顶层，this 总是 undefined。

// 如果源代码使用 eval() 执行，this 与直接调用 eval 的闭合上下文相同，或者与间接调用 eval 的 globalThis（就像它在单独的全局脚本中运行一样）相同。

function test() {
  console.log(this)
  console.log(eval('this === globalThis'))
  // 直接调用 eval
  console.log(eval('this') === this)
  // 间接调用 eval，非严格模式
  console.log(eval?.('this') === globalThis)
  // 间接调用 eval，严格模式
  console.log(eval?.("'use strict'; this") === globalThis)
}

// console.log(this === globalThis) // false
// console.log(eval('this === globalThis')) // false
// console.log(eval?.('this') === this) // false
// console.log(eval('this') === globalThis) // false
// console.log(eval?.("'use strict'; this") === globalThis) // true

// test.call({ name: 'obj' }) // false true true true
// test.call(globalThis) // true true true true

// test() // true true true true

// 对象可以作为第一个参数传递给 'call' 或 'apply'，
// 并且 'this' 将被绑定到它。
// const obj = { a: 'Custom' }

// // 使用 var 声明的变量成为 'globalThis' 的属性。
// var a = 'Global'

// function whatsThis() {
//   return this.a // 'this' 取决于函数如何被调用
// }

// whatsThis() // 'Global'; 在非严格模式下，'this' 参数默认为 'globalThis'
// obj.whatsThis = whatsThis
// obj.whatsThis() // 'Custom'; 'this' 参数被绑定到 obj

// 在非严格模式下，如果一个函数被调用时其 this 值不是一个对象，那么 this 值会被替换为一个对象。
// null 和 undefined 会变成 globalThis。
// 像 7 或 'foo' 这样的原始值会使用相关的构造函数转换为对象，所以原始数值 7 会被转换为一个 Number 包装类，字符串 'foo' 会被转换为一个 String 包装类。

function bar() {
  console.log(Object.prototype.toString.call(this))
}

// bar.call(7) // [object Number]
// bar.call('foo') // [object String]
// bar.call(undefined) // [object Window]

// 调用 f.bind(someObject) 会创建一个新函数，这个新函数具有与 f 相同的函数体和作用域，但 this 的值永久绑定到 bind 的第一个参数，无论函数如何被调用。
// function f() {
//   return this.a
// }

// const g = f.bind({ a: 'azerty' })
// console.log(g()) // azerty

// const h = g.bind({ a: 'yoo' }) // bind 只能生效一次！
// console.log(h()) // azerty

// const o = { a: 37, f, g, h }
// console.log(o.a, o.f(), o.g(), o.h()) // 37 37 azerty azerty

// class Car {
//   constructor() {
//     // 绑定 sayBye 而不是 sayHi 来展示差异
//     this.sayBye = this.sayBye.bind(this) // 这里bind之后，其他对象调用sayBye方法时，this只会指向Car对象 因为bind方法会创建一个新的函数，this值永久绑定到bind的第一个参数
//   }
//   sayHi() {
//     console.log(`Hello from ${this.name}`)
//   }
//   sayBye() {
//     console.log(`Bye from ${this.name}`)
//   }
//   get name() {
//     return 'Ferrari'
//   }
// }

// class Bird {
//   get name() {
//     return 'Tweety'
//   }
// }

// const car = new Car()
// const bird = new Bird()

// 方法中 'this' 的值取决于它们的调用者
// car.sayHi() // Hello from Ferrari
// bird.sayHi = car.sayHi
// bird.sayHi() // Hello from Tweety

// // 对于绑定方法，'this' 不依赖于调用者
// bird.sayBye = car.sayBye
// bird.sayBye() // Bye from Ferrari
